package com.kensure.shike.weixin.service;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Service;

import co.kensure.api.TokenDesc;
import co.kensure.frame.JSBaseService;
import co.kensure.http.HttpUtils;

import com.alibaba.fastjson.JSONObject;
import com.kensure.mycom.config.service.MyConfigService;
import com.kensure.shike.weixin.model.WeixinSign;

/**
 * 微信签名业务,微信公众号
 * 
 * @author fankd created on 2019-2-20
 * @since
 */
@Service
public class WeixinSignService extends JSBaseService {

	private static Map<String, TokenDesc> tokenMap = new HashMap<String, TokenDesc>();
	// 有效时间1个小时
	private static final long tokenTime = 3600 * 1000;

	/**
	 * 根据code获取WeixinOpenid
	 * 
	 * @param code
	 * @return
	 */
	public WeixinSign getSign(String url) {
		initTicket();
		WeixinSign open = sign(url);
		return open;
	}

	public String getToken() {
		initTicket();
		TokenDesc tokenDesc = tokenMap.get("access_token");
		return tokenDesc.getKey();
	}
	
	
	private synchronized void initTicket() {
		TokenDesc tokenDesc = tokenMap.get("access_token");
		long now = System.currentTimeMillis();
		if (tokenDesc == null || (now - tokenDesc.getCreatedTime().getTime()) > tokenTime) {
			String access_token = getAccessToken();
//			String ticket = getTicket(access_token);
			TokenDesc tokenDesc1 = new TokenDesc(access_token);
//			TokenDesc tokenDesc2 = new TokenDesc(ticket);
			tokenMap.put("access_token", tokenDesc1);
//			tokenMap.put("ticket", tokenDesc2);
		}
	}
	

	/**
	 * 该功能小程序和公众号通用
	 * 获取微信的 access_token 有效时间7200s
	 * 
	 * @return
	 */
	private static String getAccessToken() {
		String appid = MyConfigService.getMyConfig("weixin_appid").getVal();
		String appsecret = MyConfigService.getMyConfig("weixin_appsecret").getVal();
		String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + appsecret;
		String html = HttpUtils.getBody(url);
		String access_token = JSONObject.parseObject(html).getString("access_token");
		return access_token;
	}

	/**
	 * 获取微信的 jsapi_ticket 有效时间7200s
	 * 
	 * @return
	 */
	private static String getTicket(String access_token) {
		String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi";
		String html = HttpUtils.getBody(url);
		String ticket = JSONObject.parseObject(html).getString("ticket");
		return ticket;
	}

	/**
	 * 进行签名
	 * 
	 * @param url
	 * @return
	 */
	private static WeixinSign sign(String url) {
		String nonceStr = create_nonce_str();
		String timestamp = create_timestamp();
		String jsapi_ticket = tokenMap.get("ticket").getKey();
		// 注意这里参数名必须全部小写，且必须有序
		String string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + url;
		System.out.println(string1);
		WeixinSign weixinSign = null;
		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(string1.getBytes("UTF-8")); // 对string1 字符串进行SHA-1加密处理
			String signature = byteToHex(crypt.digest()); // 对加密后字符串转成16进制

			weixinSign = new WeixinSign();
			weixinSign.setNonceStr(nonceStr);
			weixinSign.setTimestamp(timestamp);
			weixinSign.setSignature(signature);
			String appid = MyConfigService.getMyConfig("weixin_appid").getVal();
			weixinSign.setAppid(appid);

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return weixinSign;
	}

	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	// 生成随机字符串
	private static String create_nonce_str() {
		return UUID.randomUUID().toString();
	}

	// 生成时间戳字符串
	private static String create_timestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

}
